<?php
/**
 * Created by PhpStorm.
 * User: sosyuki
 * Date: 2018/4/1
 * Time: 18:05
 */

namespace Drupal\wx_mini_program;


use EasyWeChat\Kernel\Exceptions\HttpException;
use Exception;

class WxMiniProgramController {

  protected $app;

  public function __construct() {
    $this->app = wx_mini_program_get_app();
    return $this;
  }

  function login($code) {
    $result = FALSE;
    $db_transaction = db_transaction();
    try {
      $table = 'wx_mini_program_login';
      $session = REQUEST_TIME . drupal_random_key(64);
      $mini = $this->app;
      $result = $mini->auth->session($code);
      $openid = $result['openid'];

      $name = $openid;

      $role = user_role_load_by_name('小程序访问者');
      $account = user_load_by_name($name);
      $is_new = FALSE;
      if (empty($account)) {
        $new_user = [
          'name' => $name,
          'mail' => "{$name}@{$_SERVER['SERVER_NAME']}",
          'pass' => user_password(),
          'roles' => [$role->rid => $role],
          'status' => 1,
        ];
        $is_new = TRUE;
        $account = user_save(NULL, $new_user);
      }

      db_update('users')
        ->fields([
          'access' => REQUEST_TIME,
          'login' => REQUEST_TIME,
        ])
        ->condition('uid', $account->uid)
        ->execute();
      if (variable_get_value('wx_mini_program:mini:dev')) {
        $session = $account->uid;
      }
      $fields = [
        'openid' => $result['openid'],
        'uid' => $account->uid,
        'session_key' => $result['session_key'],
        'session' => $session,
        'timestamp' => REQUEST_TIME,
      ];

      db_merge($table)
        ->fields($fields)
        ->condition('uid', $account->uid)
        ->execute();

      //登录生成 cookie
      global $user;
      $user = $account;
      $code = 0;
      $msg = 'ok';
      if ($user->status == 0) {
        $code = 2;
        $msg = '用户禁用';
      }
      drupal_alter('wx_mini_program_login', $account);

      drupal_alter('wx_mini_program_services_login', $account, $is_new);
      return [
        'code' => $code,
        'msg' => $msg,
        'user' => $account,
        'token' => $session,
        'is_new' => $is_new,
      ];
    } catch (HttpException $httpException) {
      $db_transaction->rollback();
      watchdog_exception(__FUNCTION__, $httpException);
      watchdog(__FUNCTION__, serialize($result));
      return [
        'code' => 2,
        'msg' => $httpException->formattedResponse['errmsg'],
      ];
    } catch (Exception $e) {
      $db_transaction->rollback();
      watchdog_exception(__FUNCTION__, $e);
      watchdog(__FUNCTION__, serialize($result));
      return [
        'code' => 2,
        'msg' => '系统错误,请联系管理员.',
      ];
    }
  }

  function checkLogin() {
    $session = $this->getToken();
    $table = 'wx_mini_program_login';

    $result = db_select($table)
      ->fields($table, ['uid'])
      ->condition('session', $session)
      ->execute()
      ->fetchAssoc();
    if (!empty($result)) {
      $uid = $result['uid'];
      $user = user_load($uid);
      if (!empty($user)) {

        db_update('users')
          ->fields([
            'access' => REQUEST_TIME,
            'login' => REQUEST_TIME,
          ])
          ->condition('uid', $uid)
          ->execute();

        db_update($table)
          ->fields([
            'timestamp' => REQUEST_TIME,
          ])
          ->condition('session', $session)
          ->execute();
        $is_new = FALSE;
        drupal_alter('wx_mini_program_login', $user);
        drupal_alter('wx_mini_program_services_login', $user, $is_new);
        return [
          'code' => 0,
          'user' => $user,
          'is_new' => $is_new,
        ];
      }
    }
    return ['code' => 1];
  }

  protected function getToken() {
    $headers = $this->get_headers();
    return isset($headers['Services-Mini-Token']) ? $headers['Services-Mini-Token'] : '';
  }

  function get_headers() {
    if (function_exists('apache_request_headers')) {
      // we need this to get the actual Authorization: header
      // because apache tends to tell us it doesn't exist
      $headers = apache_request_headers();

      // sanitize the output of apache_request_headers because
      // we always want the keys to be Cased-Like-This and arh()
      // returns the headers in the same case as they are in the
      // request
      $out = [];
      foreach ($headers as $key => $value) {
        $key = str_replace(
          " ",
          "-",
          ucwords(strtolower(str_replace("-", " ", $key)))
        );
        $out[$key] = $value;
      }
    }
    else {
      // otherwise we don't have apache and are just going to have to hope
      // that $_SERVER actually contains what we need
      $out = [];
      if (isset($_SERVER['CONTENT_TYPE'])) {
        $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
      }
      if (isset($_ENV['CONTENT_TYPE'])) {
        $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
      }

      foreach ($_SERVER as $key => $value) {
        if (substr($key, 0, 5) == "HTTP_") {
          // this is chaos, basically it is just there to capitalize the first
          // letter of every word that is not an initial HTTP and strip HTTP
          // code from przemek
          $key = str_replace(
            " ",
            "-",
            ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
          );
          $out[$key] = $value;
        }
      }
      // The "Authorization" header may get turned into "Auth".
      if (isset($out['Auth'])) {
        $out['Authorization'] = $out['Auth'];
      }
    }
    return $out;
  }

  function authenticate_call() {
    try {
      global $user;
      $result = $this->getUid();
      $uid = $result['uid'];
      if ($uid) {
        $account = user_load($uid);
        if (!empty($account) && $account->status == 1) {
          $user = $account;
          $user->openid = $result['openid'];
        }
      }
    } catch (Exception $e) {
      watchdog_exception(__FUNCTION__, $e);
    }
  }

  protected function getUid() {
    $session = $this->getToken();
    $table = 'wx_mini_program_login';
    $result = db_select($table)
      ->fields($table, ['uid', 'openid'])
      ->condition('session', $session)
      ->execute()->fetchAssoc();
    if (!empty($result)) {
      return $result;
    }
    return FALSE;
  }
}
